/**
 * Copyright (c) 2023 Yin. All rights reserved.
*/

#ifdef __linux__
#include <sys/types.h>
// #include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/time.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <malloc.h>
#include <errno.h>
#include "broadcast.h"
#include "cJSON.h"
#include "fun_runtime.h"
#include "version_bc.h"
#include "fun_trees.h"

#define MAX_BUFFER_LEN 1024  // send and recv buffer len
#define SEND_FREQUENCY 5    // the frequency that broadcast in net (second)

// rewrite compare function and destory function
int fun_avl_compare(AVL_NODE *node, void *key) {
    fun_avltree_unit *cp_node = (fun_avltree_unit *)node;
    return strcmp((char*)key, (char*)cp_node->key);
}
int avltree_destory_callback(AVL_NODE *pNode) {
    free(pNode);
    return 0;
}

static int tree_add_remote_info(struct broadcast_handle *bc, fun_avltree_unit *info) {
    #if BRO_USEING_MUTEX
    pthread_mutex_lock(&bc->mutex);
    if (avltree_insert(&bc->remoteList, info) != 0) {
        pthread_mutex_unlock(&bc->mutex);
        return -1;
    }
    bc->list_cnt++;
    pthread_mutex_unlock(&bc->mutex);
    #else
    if (avltree_insert(&bc->remoteList, info) != 0) {
        return -1;
    }
    bc->list_cnt++;
    #endif
    return 0;
}

static int pre_fun(AVL_NODE *pNode, void * pArg)
{
    fun_avltree_unit *unit = (fun_avltree_unit *)pNode;
    struct broadcast_handle *bc = (struct broadcast_handle *)pArg;
    return bc->getInfoCallback(&unit->r_info, bc->callbackArg);
}

int broadcast_get_remote_info(struct broadcast_handle *bc, broadcastGetRemoteInfoCallback cb, void *arg)
{
    if(!bc) return -1;
    if(cb) {
        bc->getInfoCallback = cb;
        bc->callbackArg = arg;
        return avl_tree_walk(bc->remoteList,pre_fun,bc,NULL,NULL,NULL,NULL);
    }
    return 0;
}

int broadcast_client_init(struct broadcast_handle *bc, broadcast_mode mode, char *ip, uint16_t port, long timeout)
{
    if(!bc) return -1;
    #if defined(_WIN32) || defined(_WIN64) 
    //在windows中要使用socket，需要先注册。
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD( 2, 2 );
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        sprintf(bc->msg,"fail %d\n",WSAGetLastError());
        return -1;
    }
    #endif
    bc->fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(bc->fd == -1) {
        strcpy(bc->msg,"socket fail");
        return -1;
    }
    bc->mode = mode;
    bc->timeout = timeout;
    bc->type = B_TYPE_CLIENT;
    bc->list_cnt = 0;
    bc->remoteList = NULL;
    memset(bc->version, 0, sizeof(bc->version));
    bc->paring_code.enable = false;
    bc->verified = NULL;
    bc->verifyArg = NULL;
    bc->userData = NULL;
    bc->name[0] = 0;

    if(mode == B_MODE_MOSI) {   //client to be listener
        int set = 1;
        if(setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&set, sizeof(set)) == -1) {   //set char* to adapter windows api
            strcpy(bc->msg, "setsockopt fail");
            return -1;
        }
        struct timeval tv = {timeout,0};    //first means sec, second means usec
        if (timeout >= 0) {
            #if defined(_WIN32) || defined(_WIN64) 
            DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
            setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
            #else
            setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
            #endif
        }
        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(struct sockaddr_in));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(port);
        if (ip == NULL) recvAddr.sin_addr.s_addr = INADDR_ANY;
        else recvAddr.sin_addr.s_addr = inet_addr(ip);

        if (bind(bc->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg, "bind fail");
            return -1;
        }
    } else if(mode == B_MODE_MISO) {   // client to be senter
        int optval = 1;//这个值一定要设置，否则可能导致sendto()失败
        if(setsockopt(bc->fd, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) == -1) {   // windows下需要分开设置
            strcpy(bc->msg, "setsockopt fail 1");
            return -1;
        }
        if(setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
            strcpy(bc->msg, "setsockopt fail 2");
            return -1;
        }
        struct timeval tv = {1, 0};    //first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
        #else
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        #endif
        memset(&bc->thisAddr, 0, sizeof(struct sockaddr_in));
        bc->thisAddr.sin_family = AF_INET;
        if (!ip) bc->thisAddr.sin_addr.s_addr = inet_addr("255.255.255.255");
        else     bc->thisAddr.sin_addr.s_addr = inet_addr(ip);
        bc->thisAddr.sin_port = htons(port);
    } else {
        strcpy(bc->msg, "invalid mode");
        return -1;
    }
    #if BRO_USEING_MUTEX
    if(pthread_mutex_init(&bc->mutex, NULL) != 0) {
        strcpy(bc->msg, "pthread_mutex_init fail");
        return -1;
    }
    #endif
    return 0;
}

int broadcast_client_init2(struct broadcast_handle *bc, broadcast_mode mode, char *local_ip, uint16_t port, long timeout) {
    if(!bc) return -1;
    #if defined(_WIN32) || defined(_WIN64) 
    //在windows中要使用socket，需要先注册。
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD( 2, 2 );
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        sprintf(bc->msg, "fail %d\n", WSAGetLastError());
        return -1;
    }
    #endif
    bc->fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(bc->fd == -1) {
        strcpy(bc->msg, "socket fail");
        return -1;
    }
    bc->mode = mode;
    bc->timeout = timeout;
    bc->type = B_TYPE_CLIENT;
    bc->list_cnt = 0;
    bc->remoteList = NULL;
    memset(bc->version, 0, sizeof(bc->version));
    bc->paring_code.enable = false;
    bc->verified = NULL;
    bc->verifyArg = NULL;
    bc->userData = NULL;
    bc->name[0] = 0;

    if(mode == B_MODE_MOSI) {   //client to be listener
        int set = 1;
        if(setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&set, sizeof(set)) == -1) {   //set char* to adapter windows api
            strcpy(bc->msg, "setsockopt fail");
            return -1;
        }
        struct timeval tv = {timeout, 0};    //first means sec, second means usec
        if (timeout >= 0) {
            #if defined(_WIN32) || defined(_WIN64) 
            DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
            setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
            #else
            setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
            #endif
        }
        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(struct sockaddr_in));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(port);
        if (local_ip == NULL) recvAddr.sin_addr.s_addr = INADDR_ANY;
        else recvAddr.sin_addr.s_addr = inet_addr(local_ip);

        if (bind(bc->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg, "bind fail");
            return -1;
        }
    } else if(mode == B_MODE_MISO) {   // client to be senter
        int optval = 1;     // 这个值一定要设置，否则可能导致sendto()失败
        if (setsockopt(bc->fd, SOL_SOCKET, SO_BROADCAST , (char *)&optval, sizeof(optval)) == -1) {   // windows下需要分开设置
            strcpy(bc->msg, "setsockopt fail 1");
            return -1;
        }
        if (setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
            strcpy(bc->msg, "setsockopt fail 2");
            return -1;
        }
        struct timeval tv = {1, 0};    //first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
        #else
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        #endif
        memset(&bc->thisAddr, 0, sizeof(struct sockaddr_in));
        bc->thisAddr.sin_family = AF_INET;
        bc->thisAddr.sin_addr.s_addr = inet_addr("255.255.255.255");
        bc->thisAddr.sin_port = htons(port);

        struct sockaddr_in sendAddr;
        memset(&sendAddr, 0, sizeof(struct sockaddr_in));
        sendAddr.sin_family = AF_INET;
        sendAddr.sin_port = htons(0);
        if (local_ip == NULL) sendAddr.sin_addr.s_addr = INADDR_ANY;
        else sendAddr.sin_addr.s_addr = inet_addr(local_ip);

        if (bind(bc->fd, (struct sockaddr *)&sendAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg, "bind fail");
            return -1;
        }
    } else {
        strcpy(bc->msg, "invalid mode");
        return -1;
    }
    #if BRO_USEING_MUTEX
    if(pthread_mutex_init(&bc->mutex, NULL) != 0) {
        strcpy(bc->msg, "pthread_mutex_init fail");
        return -1;
    }
    #endif
    return 0;
}

static int authentication(struct broadcast_handle *bc, char *buf, struct broadcast_remote_info *info) {
    if (!buf || !bc) return -1;
    return versionbc_verify(bc, buf, info);
}

static int generateAuthentication(struct broadcast_handle *bc,char *buf, int bufLen) {
    if (!buf || !bc) return -1;

    cJSON *root = cJSON_CreateObject();
    if (!root) return -1;

    cJSON_AddItemToObject(root, "version_bc", cJSON_CreateString(BROADCAST_VERSION));
    cJSON_AddItemToObject(root, "mode", cJSON_CreateNumber(bc->mode));
    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(bc->type));
    if (bc->paring_code.enable) cJSON_AddItemToObject(root, "code", cJSON_CreateNumber(bc->paring_code.code));
    if (bc->userData) cJSON_AddItemToObject(root, "userData", cJSON_CreateString(bc->userData));
    cJSON_AddItemToObject(root, "name", cJSON_CreateString(bc->name));

    char *out = cJSON_PrintUnformatted(root);
    strncpy(buf, out, bufLen);
	buf[bufLen-1] = 0; 

    cJSON_Delete(root);
    free(out);
    return strlen(buf);
}

static int broadcast_client_miso(struct broadcast_handle *bc) {
    int ret, len;
    char recvbuf[MAX_BUFFER_LEN], sendbuf[MAX_BUFFER_LEN];
    struct sockaddr_in recvAddr;
    int addrLen = sizeof(struct sockaddr_in);
    struct broadcast_remote_info remote_info;

    if ((len = generateAuthentication(bc, sendbuf, sizeof(sendbuf))) == -1) {
        sprintf(bc->msg, "generateAuthentication fail");
        return -1;
    }

    time_t startTime = get_timestamp();
    long nextSendTime = 0;
    do {
        // sending broadcast regular
        if (get_timestamp_difftime(startTime, get_timestamp())-nextSendTime >= 0) {
            nextSendTime += SEND_FREQUENCY;
            if ((ret = sendto(bc->fd, sendbuf, len, 0, (struct sockaddr *)&bc->thisAddr, sizeof(struct sockaddr))) == -1) {
                sprintf(bc->msg, "sendto fail, ret=%d", ret);
                return -1;
            }
            if(nextSendTime < 0) {    //overflow
                sprintf(bc->msg, "waiting too long");    //sometimes it means that program running almost 7 years
                return -1;
            }
            #ifdef BROADCAST_DEBUG
            printf("broadcast sending...\n");
            #endif
        }

        //waiting server answer
        if ((ret = recvfrom(bc->fd, recvbuf, sizeof(recvbuf), 0,
            (struct sockaddr *)&recvAddr, (socklen_t*)&addrLen)) > 0) {
            recvbuf[ret] = '\0';
            #ifdef BROADCAST_DEBUG
            printf("broadcast_client_miso recv with len %d\n",ret);
            #endif
            if (authentication(bc, recvbuf, &remote_info) == -1) {
                // printf("authentication fail!!!\n");
                continue;
            }
            
            inet_ntop(AF_INET, &recvAddr.sin_addr, remote_info.remote_ip, sizeof(remote_info.remote_ip));
            remote_info.remote_port = htons(recvAddr.sin_port);

            // add to tree
            fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit));
            if (!info) {
                strcpy(bc->msg, "malloc list fail");
                return -1;
            }
            memcpy(&info->r_info, &remote_info, sizeof(remote_info));
            info->key = info->r_info.remote_ip;
            if(tree_add_remote_info(bc, info) != 0) {
                strcpy(bc->msg, "insert info fail");
                free(info);
                continue;
            }

            #ifdef BROADCAST_DEBUG
            printf("IP:%s\n", info->r_info.remote_ip);
            printf("Port:%d\n", info->r_info.remote_port); 
            printf("receive a broadCast messgse:%s\n", recvbuf);
            #endif
        } else {
            #ifdef BROADCAST_DEBUG
            printf("recvfrom fail(%d): errno=%d, ret=%d\n", __LINE__, errno, ret);
            #endif
            if (errno != EAGAIN) {
                #if defined(_WIN32) || defined(_WIN64) 
                if (WSAGetLastError() == 10060) continue;    //overtime
                sprintf(bc->msg,"recvfrom : %d", WSAGetLastError());
                #else
                sprintf(bc->msg, "recvfrom: %m");
                #endif
                return -1;
            }
        }
    } while ((bc->timeout==-1) || (get_timestamp_difftime(startTime,get_timestamp()) < bc->timeout));
    
    sprintf(bc->msg, "timeout");
    if (bc->list_cnt <= 0) return -1;
    return 0;
}

static int broadcast_client_mosi(struct broadcast_handle *bc) {
    int ret;
    char recvbuf[MAX_BUFFER_LEN];
    struct sockaddr_in recvAddr;
    int addrLen = sizeof(struct sockaddr_in);
    struct broadcast_remote_info remote_info;

    time_t startTime = get_timestamp();
    do {
        if ((ret = recvfrom(bc->fd, recvbuf, sizeof(recvbuf), 0,
            (struct sockaddr *)&recvAddr, (socklen_t*)&addrLen)) > 0) {
            recvbuf[ret] = '\0';
            #ifdef BROADCAST_DEBUG
            printf("broadcast_client_mosi recv with len %d\n",ret);
            printf("receive a broadCast messgse:%s\n", recvbuf);
            #endif
            if (authentication(bc, recvbuf, &remote_info) == -1) {
                // printf("authentication fail!!!\n");
                continue;
            }

            if((ret = generateAuthentication(bc, recvbuf, sizeof(recvbuf))) == -1) {
                sprintf(bc->msg,"generateAuthentication fail");
                return -1;
            }
            if (sendto(bc->fd, recvbuf, ret, 0, (struct sockaddr *)&recvAddr, addrLen) < 0) {
                sprintf(bc->msg, "sendto fail");
                return -1;
            }

            avltree_destory(&bc->remoteList);
            bc->list_cnt = 0;
            bc->remoteList = NULL;

            inet_ntop(AF_INET, &recvAddr.sin_addr, remote_info.remote_ip, sizeof(remote_info.remote_ip));
            remote_info.remote_port = htons(recvAddr.sin_port);

            fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit));
            if (!info) {
                strcpy(bc->msg, "malloc list fail");
                return -1;
            }
            memcpy(&info->r_info, &remote_info, sizeof(remote_info));
            info->key = info->r_info.remote_ip;
            if(tree_add_remote_info(bc, info) != 0) {
                strcpy(bc->msg, "insert info fail");
                free(info);
                continue;
            }
      
            #ifdef BROADCAST_DEBUG
            printf("IP:%s\n", info->r_info.remote_ip);
            printf("Port:%d\n", info->r_info.remote_port); 
            #endif
            return 0;
        } else {
            #ifdef BROADCAST_DEBUG
            printf("recvfrom fail(%d): errno=%d, ret=%d\n", __LINE__, errno, ret);
            #endif
            if (errno != EAGAIN) {
                #if defined(_WIN32) || defined(_WIN64) 
                if(WSAGetLastError() == 10060) continue;    //overtime
                sprintf(bc->msg, "recvfrom : %d", WSAGetLastError());
                #else
                sprintf(bc->msg, "recvfrom: %m");
                #endif
                return -1;
            }
        }
    } while ((bc->timeout==-1) || (get_timestamp_difftime(startTime, get_timestamp()) < bc->timeout));
    
    sprintf(bc->msg, "timeout");
    return -1;
}

int broadcast_client_run(struct broadcast_handle *bc) {
    if(!bc || (bc->fd==-1) || (bc->type!=B_TYPE_CLIENT)) return -1;
    
    avltree_destory(&bc->remoteList);
    bc->list_cnt = 0;
    bc->remoteList = NULL;

    if(bc->mode == B_MODE_MOSI) {
        return broadcast_client_mosi(bc);
    } else if(bc->mode == B_MODE_MISO) {
        return broadcast_client_miso(bc);
    } else {
        return -1;
    }
}

int broadcast_server_init(struct broadcast_handle *bc, broadcast_mode mode, char *ip, uint16_t port, long timeout) {
    if (!bc) return -1;
    #if defined(_WIN32) || defined(_WIN64) 
    //在windows中要使用socket，需要先注册。
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData ) != 0 ) {
        sprintf(bc->msg, "fail %d\n",WSAGetLastError());
        return -1;
    }
    #endif
    if ((bc->fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
        strcpy(bc->msg, "socket fail");
        return -1;
    }
    // unsigned long mode1 = 0;
    // ioctlsocket(bc->fd, FIONBIO, &mode1);
    bc->mode = mode;
    bc->timeout = timeout;
    bc->type = B_TYPE_SERVER;
    bc->list_cnt = 0;
    bc->remoteList = NULL;
    memset(bc->version, 0, sizeof(bc->version));
    bc->paring_code.enable = false;
    bc->verified = NULL;
    bc->verifyArg = NULL;
    bc->userData = NULL;
    bc->name[0] = 0;

    if(mode == B_MODE_MOSI) {   //server is senter
        int optval = 1;//这个值一定要设置，否则可能导致sendto()失败
        if (setsockopt(bc->fd, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) == -1) {   // windows下需要分开设置
            strcpy(bc->msg, "setsockopt fail 1");
            return -1;
        }
        if (setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
            strcpy(bc->msg, "setsockopt fail 2");
            return -1;
        }
        struct timeval tv = {1, 0};    //first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        if (setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD)) == -1)
        #else
        if (setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) == -1)
        #endif
        {
            strcpy(bc->msg,"setsockopt fail 3");
            return -1;
        }
        memset(&bc->thisAddr, 0, sizeof(struct sockaddr_in));
        bc->thisAddr.sin_family = AF_INET;
        if(!ip) bc->thisAddr.sin_addr.s_addr = inet_addr("255.255.255.255");
        else    bc->thisAddr.sin_addr.s_addr = inet_addr(ip);
        bc->thisAddr.sin_port = htons(port);
    } else if (mode == B_MODE_MISO) {   // server is listener
        int set = 1;
        if (setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&set, sizeof(set)) == -1) {   // set char* to adapter windows api
            strcpy(bc->msg, "setsockopt fail");
            return -1;
        }
        struct timeval tv = {1, 0};    //first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
        #else
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        #endif
        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(struct sockaddr_in));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(port);
        if(ip==NULL) recvAddr.sin_addr.s_addr = INADDR_ANY;
        else recvAddr.sin_addr.s_addr = inet_addr(ip);

        if (bind(bc->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg, "bind fail");
            return -1;
        }
    } else {
        strcpy(bc->msg, "invalid mode");
        return -1;
    }
    #if BRO_USEING_MUTEX
    if(pthread_mutex_init(&bc->mutex, NULL) != 0) {
        strcpy(bc->msg, "pthread_mutex_init fail");
        return -1;
    }
    #endif
    
    return 0;
}

int broadcast_server_init2(struct broadcast_handle *bc, broadcast_mode mode, char *local_ip, uint16_t port, long timeout) {
    if (!bc) return -1;
    #if defined(_WIN32) || defined(_WIN64) 
    // 在windows中要使用socket，需要先注册。
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData ) != 0 ) {
        sprintf(bc->msg, "fail %d\n",WSAGetLastError());
        return -1;
    }
    #endif
    if ((bc->fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
        strcpy(bc->msg, "socket fail");
        return -1;
    }
    // unsigned long mode1 = 0;
    // ioctlsocket(bc->fd, FIONBIO, &mode1);
    bc->mode = mode;
    bc->timeout = timeout;
    bc->type = B_TYPE_SERVER;
    bc->list_cnt = 0;
    bc->remoteList = NULL;
    memset(bc->version, 0, sizeof(bc->version));
    bc->paring_code.enable = false;
    bc->verified = NULL;
    bc->verifyArg = NULL;
    bc->userData = NULL;
    bc->name[0] = 0;

    if(mode == B_MODE_MOSI) {   // server is senter
        int optval = 1;     // 这个值一定要设置，否则可能导致sendto()失败
        if (setsockopt(bc->fd, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) == -1) {   // windows下需要分开设置
            strcpy(bc->msg, "setsockopt fail 1");
            return -1;
        }
        if (setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
            strcpy(bc->msg, "setsockopt fail 2");
            return -1;
        }
        struct timeval tv = {1, 0};    // first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        if (setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD)) == -1)
        #else
        if (setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) == -1)
        #endif
        {
            strcpy(bc->msg,"setsockopt fail 3");
            return -1;
        }
        memset(&bc->thisAddr, 0, sizeof(struct sockaddr_in));
        bc->thisAddr.sin_family = AF_INET;
        bc->thisAddr.sin_addr.s_addr = inet_addr("255.255.255.255");
        bc->thisAddr.sin_port = htons(port);

        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(struct sockaddr_in));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(0);
        if (local_ip==NULL) recvAddr.sin_addr.s_addr = INADDR_ANY;
        else recvAddr.sin_addr.s_addr = inet_addr(local_ip);
        if (bind(bc->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg, "bind fail");
            return -1;
        }
    } else if (mode == B_MODE_MISO) {   // server is listener
        int set = 1;
        if(setsockopt(bc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&set, sizeof(set)) == -1) {   // set char* to adapter windows api
            strcpy(bc->msg, "setsockopt fail");
            return -1;
        }
        struct timeval tv = {1, 0};    // first means sec, second means usec
        #if defined(_WIN32) || defined(_WIN64) 
        DWORD timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(DWORD));
        #else
        setsockopt(bc->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        #endif
        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(struct sockaddr_in));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(port);
        if (local_ip==NULL) recvAddr.sin_addr.s_addr = INADDR_ANY;
        else recvAddr.sin_addr.s_addr = inet_addr(local_ip);

        if (bind(bc->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1) {
            strcpy(bc->msg,"bind fail");
            return -1;
        }
    } else {
        strcpy(bc->msg, "invalid mode");
        return -1;
    }
    #if BRO_USEING_MUTEX
    if(pthread_mutex_init(&bc->mutex, NULL) != 0) {
        strcpy(bc->msg, "pthread_mutex_init fail");
        return -1;
    }
    #endif
    
    return 0;
}

static int broadcast_server_mosi(struct broadcast_handle *bc) {
    int ret,len;
    char recvbuf[MAX_BUFFER_LEN], sendbuf[MAX_BUFFER_LEN];
    struct sockaddr_in recvAddr;
    int addrLen = sizeof(struct sockaddr_in);
    struct broadcast_remote_info remote_info;

    if((len = generateAuthentication(bc, sendbuf, sizeof(sendbuf))) == -1) {
        sprintf(bc->msg, "generateAuthentication fail");
        return -1;
    }

    time_t startTime = get_timestamp();
    long nextSendTime = 0;
    do {
        // sending broadcast regular
        if (get_timestamp_difftime(startTime, get_timestamp())-nextSendTime >= 0) {
            nextSendTime += SEND_FREQUENCY;
            if((ret = sendto(bc->fd, sendbuf, len, 0, (struct sockaddr *)&bc->thisAddr, sizeof(struct sockaddr))) == -1) {
                sprintf(bc->msg, "sendto fail, ret=%d\n", ret);
                return -1;
            }
            if(nextSendTime < 0) {    // overflow
                sprintf(bc->msg, "waiting too long");    // sometimes it means that program running almost 7 years
                return -1;
            }
            #ifdef BROADCAST_DEBUG
            printf("broadcast sending...\n");
            #endif
        }

        // waiting client answer
        if ((ret = recvfrom(bc->fd, recvbuf, sizeof(recvbuf), 0,
            (struct sockaddr *)&recvAddr, (socklen_t*)&addrLen)) > 0) {
            recvbuf[ret] = '\0';
            #ifdef BROADCAST_DEBUG
            printf("broadcast_server_mosi recv with len %d\n",ret);
            #endif
            if(authentication(bc, recvbuf, &remote_info) == -1) {
                // printf("authentication fail!!!\n");
                continue;
            }
    
            inet_ntop(AF_INET, &recvAddr.sin_addr, remote_info.remote_ip, sizeof(remote_info.remote_ip));
            remote_info.remote_port = htons(recvAddr.sin_port);

            fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit));
            if (!info) {
                strcpy(bc->msg, "malloc list fail");
                return -1;
            }
            memcpy(&info->r_info, &remote_info, sizeof(remote_info));
            info->key = info->r_info.remote_ip;
            if (tree_add_remote_info(bc, info) != 0) {
                strcpy(bc->msg, "insert info fail");
                free(info);
                continue;
            }
            #ifdef BROADCAST_DEBUG
            printf("IP:%s\n", info->r_info.remote_ip);
            printf("Port:%d\n", info->r_info.remote_port); 
            printf("receive a broadCast messgse:%s\n", recvbuf);
            #endif
        } else {
            #ifdef BROADCAST_DEBUG
            printf("recvfrom fail(%d): errno=%d, ret=%d\n",__LINE__, errno, ret);
            #endif
            if(errno != EAGAIN){
                #if defined(_WIN32) || defined(_WIN64) 
                if(WSAGetLastError() == 10060) continue;    //overtime
                sprintf(bc->msg, "recvfrom : %d", WSAGetLastError());
                #else
                sprintf(bc->msg, "recvfrom: %m");
                #endif
                return -1;
            }
        }
    } while ((bc->timeout==-1) || (get_timestamp_difftime(startTime, get_timestamp()) < bc->timeout));
    
    sprintf(bc->msg, "timeout");
    if (bc->list_cnt <= 0) return -1;
    return 0;
}

static int broadcast_server_miso(struct broadcast_handle *bc) {
    int ret;
    char recvbuf[MAX_BUFFER_LEN];
    struct sockaddr_in recvAddr;
    int addrLen = sizeof(struct sockaddr_in);
    struct broadcast_remote_info remote_info;

    time_t startTime = get_timestamp();
    do {
        if ((ret = recvfrom(bc->fd, recvbuf, sizeof(recvbuf), 0,
            (struct sockaddr *)&recvAddr, (socklen_t*)&addrLen)) > 0) {
            recvbuf[ret] = '\0';
            #ifdef BROADCAST_DEBUG
            printf("broadcast_server_miso recv with len %d\n",ret);
            #endif
            if (authentication(bc, recvbuf, &remote_info) == -1) {
                // printf("authentication fail!!!\n");
                continue;
            }

			#ifdef BROADCAST_DEBUG
            printf("receive a broadCast messgse:%s\n", recvbuf);
            #endif

            if ((ret = generateAuthentication(bc, recvbuf, sizeof(recvbuf))) == -1) {
                sprintf(bc->msg, "generateAuthentication fail");
                return -1;
            }
            if(sendto(bc->fd, recvbuf, ret, 0, (struct sockaddr *)&recvAddr, addrLen) < 0) {
                sprintf(bc->msg, "sendto fail");
                return -1;
            }

            inet_ntop(AF_INET, &recvAddr.sin_addr, remote_info.remote_ip, sizeof(remote_info.remote_ip));
            remote_info.remote_port = htons(recvAddr.sin_port);

            fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit));
            if (!info) {
                strcpy(bc->msg, "malloc list fail");
                return -1;
            }
            memcpy(&info->r_info, &remote_info, sizeof(remote_info));
            info->key = info->r_info.remote_ip;
            if (tree_add_remote_info(bc,info) != 0) {
                strcpy(bc->msg,"insert info fail");
                free(info);
                continue;
            }

            #ifdef BROADCAST_DEBUG
            printf("IP:%s\n", info->r_info.remote_ip);
            printf("Port:%d\n", info->r_info.remote_port); 
            #endif
            return 0;
        } else {
            #ifdef BROADCAST_DEBUG
            printf("recvfrom fail(%d): errno=%d, ret=%d\n",__LINE__, errno, ret);
            #endif
            if(errno != EAGAIN){
                #if defined(_WIN32) || defined(_WIN64) 
                if(WSAGetLastError() == 10060) continue;    //overtime
                sprintf(bc->msg, "recvfrom : %d", WSAGetLastError());
                #else
                sprintf(bc->msg, "recvfrom: %m");
                #endif
                return -1;
            }
        }
    } while ((bc->timeout==-1) || (get_timestamp_difftime(startTime,get_timestamp()) < bc->timeout));
    
    if(bc->list_cnt <= 0) {
        sprintf(bc->msg,"timeout");
        return -1;
    }
    return 0;
}

int broadcast_server_run(struct broadcast_handle *bc) {
    if(!bc || (bc->fd==-1) || (bc->type!=B_TYPE_SERVER)) return -1;
    
    avltree_destory(&bc->remoteList);
    bc->list_cnt = 0;
    bc->remoteList = NULL;

    if(bc->mode == B_MODE_MOSI) {
        return broadcast_server_mosi(bc);
    } else if(bc->mode == B_MODE_MISO) {
        return broadcast_server_miso(bc);
    } else {
        return -1;
    }
}

int broadcast_close(struct broadcast_handle *bc) {
    close(bc->fd);
    bc->fd = -1;
    avltree_destory(&bc->remoteList);
    bc->remoteList = NULL;
    if (bc->userData) free(bc->userData);
    bc->userData = NULL;
    #if BRO_USEING_MUTEX
    pthread_mutex_destroy(&bc->mutex);
    #endif
    return 0;
}

char *broadcast_getErr(struct broadcast_handle *bc) {
    return bc->msg;
}

static int get_info_demo(struct broadcast_remote_info *info, void *arg) {
    printf("get remote ip: %s, port :%d\n", info->remote_ip, info->remote_port);
    return 0;
}

#ifdef __linux__
int bind_to_device(struct broadcast_handle *bc, char *name) {
    // #include <net/if.h>
    // struct ifreq iq;
    // strcpy(iq.ifr_name, name);
    if(setsockopt(bc->fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1) < 0) {
        sprintf(bc->msg, "setsockopt fail 3, %m");
        return -1;
    }
    return 0;
}
#endif  /* __linux__ */

char *broadcast_get(char *ip, char *mask) {
    in_addr_t m = inet_addr(mask);
    struct in_addr o;
    o.s_addr = (inet_addr(ip) & m) | ~m;
    return inet_ntoa(o);
}

int set_pairing_code(struct broadcast_handle *bc, int code) {
    if (!bc) return -1;
    bc->paring_code.enable = true;
    bc->paring_code.code = code;
    #ifdef BROADCAST_DEBUG
    printf("enable code!!!\n");
    #endif
    return 0;
}

int set_user_verify(struct broadcast_handle *bc, char *data, int data_len, bool (*verify)(char *, void *), void *arg) {
    if (!bc) return -1;

    bc->verified = verify;
    bc->verifyArg = arg;
    if (bc->userData) free(bc->userData);
    bc->userData = malloc(data_len + 1);
    if (!bc->userData) return -1;
    memcpy(bc->userData, data, data_len);
    bc->userData[data_len] = 0;
    #ifdef BROADCAST_DEBUG
    printf("enable verify!!!\n");
    #endif
    return 0;
}

const char* broadcast_version(void) {
    return BROADCAST_VERSION;
}

int set_device_name(struct broadcast_handle *bc, char *name) {
    strncpy(bc->name, name, sizeof(bc->name)-1);
    bc->name[sizeof(bc->name)-1] = 0;
    return 0;
}

static void client_demo()
{
    struct broadcast_handle client;
    if(broadcast_client_init(&client, B_MODE_MOSI, NULL, 4090, -1) < 0) {
        printf("broadcast_client_init fail: %s\n", broadcast_getErr(&client));
        broadcast_close(&client);
        return;
    }
    if(broadcast_client_run(&client) < 0) {
        printf("broadcast_client_run fail: %s\n", broadcast_getErr(&client));
        broadcast_close(&client);
        return;
    }
    if(broadcast_get_remote_info(&client, get_info_demo, NULL) < 0) {
        printf("err happened when running broadcast_get_remote_info\n");
    }
    broadcast_close(&client);
}

static void server_demo() {
    struct broadcast_handle server;
    if(broadcast_server_init(&server, B_MODE_MOSI, NULL, 4090, 10) < 0) {
        printf("broadcast_server_init fail: %s\n", broadcast_getErr(&server));
        broadcast_close(&server);
        return;
    }
    if(broadcast_server_run(&server) < 0) {
        printf("broadcast_server_run fail: %s\n", broadcast_getErr(&server));
        broadcast_close(&server);
        return;
    }
    if(broadcast_get_remote_info(&server, get_info_demo, NULL) < 0) {
        printf("err happened when running broadcast_get_remote_info\n");
    }
    broadcast_close(&server);
}

#if 0    
int client()
{
    int sockListen;
    if((sockListen = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
        printf("socket fail\n");
        return -1;
    }
    int set = 1;
    setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(int));
    struct sockaddr_in recvAddr;
    memset(&recvAddr, 0, sizeof(struct sockaddr_in));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_port = htons(4001);
    recvAddr.sin_addr.s_addr = INADDR_ANY;
    // 必须绑定，否则无法监听
    if(bind(sockListen, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1){
        printf("bind fail\n");
        return -1;
    }
    int recvbytes;
    char recvbuf[128];
    int addrLen = sizeof(struct sockaddr_in);
    if((recvbytes = recvfrom(sockListen, recvbuf, 128, 0,
        (struct sockaddr *)&recvAddr, &addrLen)) != -1){
        recvbuf[recvbytes] = '\0';
        printf("receive a broadCast messgse:%s\n", recvbuf);
    }else{
        printf("recvfrom fail\n");
    }
    close(sockListen);
    return 0;
}

int server()
{
    char msg[128] = "I am broadCast message from server!";
    int brdcFd;
    if((brdcFd = socket(PF_INET, SOCK_DGRAM, 0)) == -1){
        printf("socket fail\n");
        return -1;
    }
    int optval = 1;//这个值一定要设置，否则可能导致sendto()失败
    setsockopt(brdcFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optval, sizeof(int));
    struct sockaddr_in theirAddr;
    memset(&theirAddr, 0, sizeof(struct sockaddr_in));
    theirAddr.sin_family = AF_INET;
    theirAddr.sin_addr.s_addr = inet_addr("255.255.255.255");
    theirAddr.sin_port = htons(4001);
    int sendBytes;
    if((sendBytes = sendto(brdcFd, msg, strlen(msg), 0,
            (struct sockaddr *)&theirAddr, sizeof(struct sockaddr))) == -1){
        printf("sendto fail, errno=%d\n", errno);
        return -1;
    }
    printf("msg=%s, msgLen=%d, sendBytes=%d\n", msg, strlen(msg), sendBytes);
    close(brdcFd);
    return 0;
}
#endif